package com.changgou.utils;

import com.alibaba.fastjson.JSON;
import com.changgou.common.CommonCode;
import com.changgou.exception.ExceptionCast;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private ValueOperations<String,String> valueOperations;

    @Autowired
    private HashOperations<String,String,Object> hashOperations;

    @Autowired
    private ListOperations<String,Object> listOperations;

    @Autowired
    private SetOperations<String,Object> setOperations;

    @Autowired
    private ZSetOperations<String,Object> zSetOperations;
    // 默认过期时间 单位秒
    public static  final long DEFAULT_EXPIRE = 60 * 60 * 24;
    // 不设置过期时长
    public static  final  long NOT_EXPIRE = -1;

    private static  final Gson gson = new Gson();

    // 设置缓存失效时间
    public boolean expire(String key,long  expire){

        try {
            if(expire > 0){
                redisTemplate.expire(key,expire,TimeUnit.SECONDS);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }



    // 获取key的失效时间
    public long getExpire(String key){
        return  redisTemplate.getExpire(key);
    }

    // 判断key是否存在
    public boolean hasKey(String key){
        try {
            return  redisTemplate.hasKey(key);
        }catch (Exception e){
            return  false;
        }
    }

    /**
    *@Description  删除缓存 可以删除一个值或者多个
    *@Param String... key
    *@Return void
    *@Author feilx
    */
    public void del(String... key){
        if(key !=null && key.length > 0){
            if(key.length == 1){
                redisTemplate.delete(key[0]);
            }else{
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    // 设置值 并设置失效时间
    public void set(String key, Object value, long expire){
        valueOperations.set(key,toJson(value));
        if(expire != NOT_EXPIRE){
            redisTemplate.expire(key,expire, TimeUnit.SECONDS);
        }
    }

    // 设置值 不设置失效时间
    public void set(String key, Object value){
        valueOperations.set(key,toJson(value));
    }

    // 获取值  并设置过期时间
    public <T> T get(String key,Class<T> clazz, long expire){
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE) {
            redisTemplate.expire(key,expire,TimeUnit.SECONDS);
        }
        return  value == null ? null : fromJson(value, clazz);
    }
    //获取值  并设置过期时间
    public String get(String key,long expire){
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE){
            redisTemplate.expire(key,expire,TimeUnit.SECONDS);
        }
        return value;
    }

    // 获取字符串值
    public String get(String key){
        String value = valueOperations.get(key);
        return value;
    }
    // 获取对象值
    public <T> T get(String key,Class<T> clazz){
        String value = valueOperations.get(key);
        return  value == null ? null : fromJson(value,clazz);
    }

    /**
    *@Description 递增 要增加大于1
    *@Param  key data
    *@Return long
    *@Author feilx
    */
    public long incr(String key, long incr){
        if(incr <  0){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        return valueOperations.increment(key,incr);
    }
    /**
    *@Description
    *@Param key decr 减少因子
    *@Return
    *@Author feilx
    */
    public long decr(String key, long decr){
        if(decr < 0){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        return  valueOperations.decrement(key,decr);
    }


    /**
    *@Description  HhashGet 获取hashkey对应的值
    *@Param  key 键  item元素
    *@Return
    *@Author feilx
    */
    public Object hget(String key,String item){
        return  hashOperations.get(key,item);
    }

    /**
    *@Description 获取hashKey对应的所有键值
    *@Param  key 键
    *@Return
    *@Author feilx
    */
    public Map<String,Object> hmget(String key){
        return hashOperations.entries(key);
    }
    /**
    *@Description  hash 设置多个数据
    *@Param  key 键 map 键值对数据
    *@Return
    *@Author feilx
    */
    public boolean hmset(String key,Map<String,Object> map){
        try {
           hashOperations.putAll(key,map);
           return true;
        }catch (Exception e){
           e.printStackTrace();
           return false;
        }
    }
    /**
    *@Description  hash 设置多个数据 并设置失效时间
    *@Param  key 键  map 对应对个键值对  expire失效时间
    *@Return
    *@Author feilx
    */
    public boolean hmset(String key,Map<String,Object> map,long expire){
        try {
            hashOperations.putAll(key,map);
            if(expire > 0){
                expire(key,expire);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
    /**
    *@Description  向hash表中放入数据，如果不存在将创建
    *@Param    key键   item 项  value值
    *@Return  true or false
    *@Author feilx
    */
    public boolean hset(String key,String item,Object value){
          try {
              hashOperations.put(key,item,toJson(value));
              return true;
          }catch (Exception e){
              e.printStackTrace();
              return  false;
          }
    }
    /**
     *@Description  向hash表中放入数据，如果不存在将创建
     *@Param    key键   item 项  value值
     *@Return  true or false
     *@Author feilx
     */
    public boolean hset(String key,String item,Object value,long expire){
        try {
            hashOperations.put(key,item,toJson(value));
            if(expire > 0){
                expire(key, expire);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }

    /**
    *@Description  根据key获取 所有的key
    *@Param
 * @param key
    *@Return java.util.Set<java.lang.String>
    *@Author feilx
    */
   public Set<String> hkeys(String key){
        return hashOperations.keys(key);
   }
   /**
   *@Description 获取所有的值
   *@Param
 * @param key
   *@Return java.util.List<java.lang.Object>
   *@Author feilx
   */

   public List<Object> hvalues(String key){
       return hashOperations.values(key);
   }


    /**
    *@Description  判断hash表中是否有该值
    *@Param   key键  item项
    *@Return
    *@Author feilx
    */
    public boolean hasHashKey(String key,String item){
        return hashOperations.hasKey(key,item);
    }

    /**
    *@Description  hash递增 不存在则创建一个，并把新增后的值返回
    *@Param  key 键  item 项  hincr 递增因子
    *@Return
    *@Author feilx
    */
    public long hincr(String key,String item,long hincr){
        return hashOperations.increment(key,item,hincr);
    }
    /**
     *@Description  hash递减 不存在则创建一个，并把新增后的值返回
     *@Param  key 键  item 项  hincr 递减因子
     *@Return
     *@Author feilx
     */
    public long hdecr(String key,String item,long hdecr){
        return hashOperations.increment(key,item,hdecr);
    }

    /**
    *@Description  hash 根据键 项 删除
    *@Param
     * @param key  键
     * @param item  项
    *@Return long
    *@Author feilx
    */
    public long hDelete(String key,String item){
        return hashOperations.delete(key, item);
    }

    /**
    *@Description 获取hash中 值的个数
    *@Param
 * @param key 键
    *@Return long
    *@Author feilx
    */
    public long hsize(String key){
       return hashOperations.size(key);
    }

    /**
     * Set String 类型的无序集合。集合成员是唯一的，这就意味着集合中不能出现重复的数据。
     * 最多存储2的32次方-1 数据
     */

    /**
    *@Description  set 根据key获取所有的值
    *@Param  key 键
    *@Return
    *@Author feilx
    */
    public Set<Object> setGet(String key){
        try {
            return setOperations.members(key);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
    *@Description  根据value从一个set中查询，是否存在
    *@Param     key 键  value 值
    *@Return
    *@Author feilx
    */
    public boolean hasSetKey(String key,Object value){
        try {
            return setOperations.isMember(key,toJson(value));
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
    *@Description 向set中加入缓存数据
    *@Param  key 键
     *@Param values 值 可以是多个
    *@Return
    *@Author feilx
    */
    public long sAdd(String key,Object... values){
        try {
            return setOperations.add(key,values);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }


    /**
    *@Description  向set中设置值 并设置失效时间
    *@Param
     * @param key 键
     * @param exprie  失效时间
     * @param values  值可以是多个
    *@Return long 成功个数
    *@Author feilx
    */
    public long sAdd(String key,long exprie,Object... values){
        try{
            Long count = setOperations.add(key, values);
            if(exprie > 0){
                expire(key,exprie);
            }
            return  count;
        }catch (Exception e){
           e.printStackTrace();
           return 0;
        }
    }
    /**
    *@Description
    *@Param
     * @param key 键
    *@Return long  set缓存长度
    *@Author feilx
    */
    public long sGetSetSize(String key){
        try{
            return setOperations.size(key);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
    *@Description   移除set中的value值
    *@Param
     * @param key  键
     * @param values  值 可以多个
    *@Return long
    *@Author feilx
    */
    public long setRemove(String key,Object... values){
        try {
           return setOperations.remove(key, values);

        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }
    /**
    *@Description 获取list缓存的内容
    *@Param
     * @param key   键
     * @param start 开始
     * @param end   结束 0 -1代表所有值
    *@Return java.util.List<java.lang.Object>
    *@Author feilx
    */
    public List<Object> lGet(String key, long start, long end){
        try {
            return listOperations.range(key,start,end);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
    *@Description  获取list缓存的长度
    *@Param
     * @param key  键
    *@Return long
    *@Author feilx
    */
    public long lGetListSize(String key){
        try {
            return listOperations.size(key);
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }
    /**
    *@Description  通过索引获取list中的值
    *@Param
     * @param key  键
     * @param index 索引 index>=0时， 0表头，1第二个越少 index<0 时 -1 最后一个数 -2倒数第二个数
    *@Return java.lang.Object
    *@Author feilx
    */
    public Object lGetIndex(String key,long index){
        try {
            return listOperations.size(key);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
    *@Description  list缓存中右边添加缓存
    *@Param
     * @param key  键
     * @param values  值
    *@Return boolean
    *@Author feilx
    */
    public boolean listRightSet(String key,List<Object> values){
        try {
            if(values.size() == 1){
                listOperations.rightPush(key,toJson(values.get(0)));
            }else{
                listOperations.rightPushAll(key,toJson(values));
            }
            return  true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }

    }
    /**
    *@Description list缓存中右边添加缓存并设置失效时间
    *@Param
     * @param key   键
     * @param expire  失效时间
     * @param values  值
    *@Return boolean
    *@Author feilx
    */
    public boolean listRightSet(String key,long expire,List<Object> values){
        try {
            if(values.size() == 1){
                listOperations.rightPush(key,toJson(values.get(0)));
            }else{
                listOperations.rightPushAll(key,toJson(values));
            }
            if(expire > 0){
                expire(key,expire);
            }
            return  true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }
    /**
    *@Description  根据索引修改list中的某条数据
    *@Param
     * @param key 键值
     * @param index 索引
     * @param value 值
    *@Return boolean
    *@Author feilx
    */
    public boolean listUpdateByIndex(String key,long index,Object value){
        try{
            listOperations.set(key, index, toJson(value));
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }
     /**
     *@Description
     *@Param
      * @param key  键
      * @param count  移除多少个
      * @param value  值
     *@Return long   移除的个数
     *@Author feilx
     */
     public long listRemove(String key,long count,Object value){
        try {
            return listOperations.remove(key,count,toJson(value));
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
     }

     /*
     *  sorted set Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

          不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。 */

     // 有序集合
    /**
    *@Description   有序set添加元素
    *@Param
     * @param key  键
     * @param value  值
     * @param score  分数
    *@Return boolean
    *@Author feilx
    */
    public boolean zset(String key,Object value,double score){
        return zSetOperations.add(key,toJson(value),score);
    }



    public void zIncrementScore(String key, Object value, long delta) {
        zSetOperations.incrementScore(key, value, delta);
    }

    public void zUnionAndStore(String key, Collection otherKeys, String destKey) {
        zSetOperations.unionAndStore(key, otherKeys, destKey);
    }

    /**
    *@Description
    *@Param
     * @param key  键
     * @param value 值
    *@Return long
    *@Author feilx
    */
    public long getZsetSize(String key,Object value){
        Double score = zSetOperations.score(key, toJson(value));
        if(score == null){
            return 0;
        }else{
            return score.longValue();
        }
    }


    //object转成JSON数据
    private String toJson(Object object){
        if(object instanceof Integer || object instanceof Long
          || object instanceof Double || object instanceof Boolean || object instanceof String){
            return  String.valueOf(object); //基本数据类型转换String
        }
        return gson.toJson(object);
    }
    // JSON 转object
    private <T> T fromJson(String json,Class<T> claszz){
      return gson.fromJson(json,claszz);
    }



}
